<?php
namespace app\popo;


use app\exception\DynamicMethodException;
use support\exception\BusinessException;
use support\Log;

abstract class BaseVO
{
    // 用于存储对象属性的数组
    protected $data = [];

    // 魔术方法，当设置不存在的属性时调用
    public function __set($name, $value)
    {
        // 将下划线命名转换为驼峰命名
        $camelCaseName = $this->underscoreToCamelCase($name);
        $this->data[$camelCaseName] = $value;
    }

    // 魔术方法，当获取不存在的属性时调用
    public function __get($name)
    {
        // 将下划线命名转换为驼峰命名
        $camelCaseName = $this->underscoreToCamelCase($name);
        return $this->data[$camelCaseName] ?? null;
    }

    // 将下划线命名转换为驼峰命名的方法
    private function underscoreToCamelCase($string): string
    {
        return lcfirst(str_replace('_', '', ucwords($string, '_')));
    }


    // 设置对象属性的方法
    public function setData(array $data): void
    {
        $classProperties = array_keys(get_class_vars(get_called_class()));
        foreach ($data as $key => $value) {
            $camelCaseName = $this->underscoreToCamelCase($key);
            if (in_array($camelCaseName, $classProperties)) {
                $methodName = ucfirst($camelCaseName);
                $methodName = "set$methodName";
                $this->$methodName($camelCaseName, $value);
            }
        }
    }

    // 生成自定义的setter方法

    /**
     * @throws BusinessException
     */
    public function __call($name, $arguments)
    {
        if (str_starts_with($name, 'set')) {
            if (isset($arguments[0])) {
                $this->data[$arguments[0]] = $arguments[1];
            } else {
                throw new DynamicMethodException("Setter method {$name} requires an argument.");
            }
        } else {
            // 如果不是以set开头的方法且未找到对应的处理，抛出异常
            throw new DynamicMethodException("Method {$name} does not exist.");
        }
    }

    // 将对象转换为数组的方法，方便在某些场景下使用（如传递给数据库操作函数等）
    public function toArray()
    {
        return $this->data;
    }

    public static function fromArray(array $data): static
    {
        $self = (new static());
        $self->setData($data);

        return $self;
    }
}